﻿using System;
using System.Collections.Specialized;
using System.Configuration;
using System.Data;
using System.Data.Common;

namespace Altairis.MailToolkit {

    internal static class ExtensionMethods {
        // Configuration reading utils

        public static string GetConfigValue(this NameValueCollection config, string name, string defaultValue) {
            // Validate arguments
            if (config == null) throw new ArgumentNullException("config");
            if (name == null) throw new ArgumentNullException("name");
            if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "name");

            // Check if we have value in collection
            if (Array.IndexOf(config.AllKeys, name) > -1) {
                var r = config[name];
                config.Remove(name);
                return r;
            }
            else {
                return defaultValue;
            }
        }

        public static int GetConfigValue(this NameValueCollection config, string name, int defaultValue) {
            // Validate arguments
            if (config == null) throw new ArgumentNullException("config");
            if (name == null) throw new ArgumentNullException("name");
            if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "name");

            // Check if we have value in collection
            if (Array.IndexOf(config.AllKeys, name) > -1) {
                int r;
                var parsed = int.TryParse(config[name], out r);
                if (!parsed) throw new System.Configuration.ConfigurationErrorsException(string.Format("Value of the \"{0}\" attribute is not valid Int32.", name));
                config.Remove(name);
                return r;
            }
            else {
                return defaultValue;
            }
        }

        public static bool GetConfigValue(this NameValueCollection config, string name, bool defaultValue) {
            // Validate arguments
            if (config == null) throw new ArgumentNullException("config");
            if (name == null) throw new ArgumentNullException("name");
            if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "name");

            // Check if we have value in collection
            if (Array.IndexOf(config.AllKeys, name) > -1) {
                bool r;
                var parsed = bool.TryParse(config[name], out r);
                if (!parsed) throw new System.Configuration.ConfigurationErrorsException(string.Format("Value of the \"{0}\" attribute is not valid Boolean.", name));
                config.Remove(name);
                return r;
            }
            else {
                return defaultValue;
            }
        }

        public static T GetConfigValue<T>(this NameValueCollection config, string name, T defaultValue) where T : struct {
            if (config == null) throw new ArgumentNullException("config");
            if (name == null) throw new ArgumentNullException("name");
            if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be empty or whitespace only string.", "name");
            if (!typeof(T).IsEnum) throw new ArgumentException("Generic type must be enum");

            if (Array.IndexOf(config.AllKeys, name) > -1) {
                T r;
                var parsed = Enum.TryParse<T>(config[name], out r);
                if (!parsed) throw new System.Configuration.ConfigurationErrorsException(string.Format("Value of the \"{0}\" attribute is not valid {1}.", name, typeof(T)));
                config.Remove(name);
                return r;
            }
            else {
                return defaultValue;
            }
        }

        // DB connection utils

        public static DbConnection CreateDbConnection(this ConnectionStringSettings settings) {
            // Validate arguments
            if (settings == null) throw new ArgumentNullException("settings");
            if (string.IsNullOrEmpty(settings.ProviderName)) throw new ArgumentException("The ProviderName property cannot be empty.", "settings");
            if (string.IsNullOrEmpty(settings.ConnectionString)) throw new ArgumentException("The ConnectionString property cannot be empty.", "settings");

            var factory = DbProviderFactories.GetFactory(settings.ProviderName);
            var conn = factory.CreateConnection();
            conn.ConnectionString = settings.ConnectionString;
            return conn;
        }

        // DB parameter utils

        public static void AddParameterWithValue(this DbCommand cmd, string name, string value) {
            var p = cmd.CreateParameter();
            p.ParameterName = name;
            p.DbType = DbType.String;
            if (!string.IsNullOrEmpty(value)) p.Size = value.Length;
            if (string.IsNullOrWhiteSpace(value)) {
                p.Value = DBNull.Value;
            }
            else {
                p.Value = value;
            }

            cmd.Parameters.Add(p);
        }

        public static void AddParameterWithValue(this DbCommand cmd, string name, int value) {
            var p = cmd.CreateParameter();
            p.ParameterName = name;
            p.DbType = DbType.Int32;
            p.Value = value;
            cmd.Parameters.Add(p);
        }

        public static void AddParameterWithValue(this DbCommand cmd, string name, Guid value) {
            var p = cmd.CreateParameter();
            p.ParameterName = name;
            p.DbType = DbType.Guid;
            p.Value = value;
            cmd.Parameters.Add(p);
        }

        public static void AddParameterWithValue(this DbCommand cmd, string name, DateTime value) {
            var p = cmd.CreateParameter();
            p.ParameterName = name;
            p.DbType = DbType.DateTime;
            p.Value = value;
            cmd.Parameters.Add(p);
        }

        public static void AddParameterWithValue(this DbCommand cmd, string name, bool value) {
            var p = cmd.CreateParameter();
            p.ParameterName = name;
            p.DbType = DbType.Boolean;
            p.Value = value;
            cmd.Parameters.Add(p);
        }

        public static void AddParameterWithValue(this DbCommand cmd, string name, byte[] value) {
            var p = cmd.CreateParameter();
            p.ParameterName = name;
            p.DbType = DbType.Binary;
            p.Size = value.Length;
            p.Value = value;
            cmd.Parameters.Add(p);
        }
    }
}